package cHelper

import (
	"encoding/json"
	"reflect"
	"strings"
)

func fieldValues(field string, data []interface{}) []interface{} {
	result := []interface{}{}
	for _, dataItem := range data {
		if field == "*" {
			if !IsSlice(dataItem) {
				result = append(result, nil)
			} else {
				value := reflect.ValueOf(dataItem)
				len := value.Len()
				for i := 0; i < len; i++ {
					item := value.Index(i)
					if item.CanInterface() {
						result = append(result, item.Interface())
					} else {
						result = append(result, nil)
					}
				}
			}
		} else if IsStruct(dataItem) {
			dataItemType := reflect.TypeOf(dataItem).Elem()
			dataItemValue := reflect.ValueOf(dataItem).Elem()
			len := dataItemType.NumField()
			match := false
			for i := 0; i < len; i++ {
				dataItemFieldName := dataItemType.Field(i).Name
				if dataItemFieldName != field {
					continue
				}
				match = true
				dataItemFieldValue := dataItemValue.FieldByName(dataItemFieldName)
				if dataItemFieldValue.CanInterface() {
					result = append(result, dataItemFieldValue.Interface())
				} else {
					result = append(result, nil)
				}
				break
			}
			if !match {
				result = append(result, nil)
			}
		} else if IsMap(dataItem) {
			dataItemValue := reflect.ValueOf(dataItem)
			i := dataItemValue.MapRange()
			match := false
			for i.Next() {
				if i.Key().String() != field {
					continue
				}
				match = true
				dataItemFieldValue := i.Value()
				if dataItemFieldValue.CanInterface() {
					result = append(result, dataItemFieldValue.Interface())
				} else {
					result = append(result, nil)
				}
			}
			if !match {
				result = append(result, nil)
			}
		} else {
			result = append(result, nil)
		}
	}
	return result
}

func GetFieldValues(field string, data interface{}) []interface{} {
	fields := strings.Split(field, ".")
	fieldsData := [][]interface{}{}
	fieldsData = append(fieldsData, []interface{}{data})

	for index, fieldItem := range fields {
		tempData := fieldValues(fieldItem, fieldsData[index])
		fieldsData = append(fieldsData, tempData)
	}

	return fieldsData[len(fields)]
}

func GetFieldValue(field string, data interface{}) interface{} {
	fields := strings.Split(field, ".")
	fieldsData := [][]interface{}{}
	fieldsData = append(fieldsData, []interface{}{data})

	for index, fieldItem := range fields {
		tempData := fieldValues(fieldItem, fieldsData[index])
		fieldsData = append(fieldsData, tempData)
	}

	result := fieldsData[len(fields)]

	if InArray(fields, "*") {
		return result
	} else if len(result) > 0 {
		return result[0]
	} else {
		return nil
	}
}

func SwitchStruct[A any, B any](source A, target B) error {
	var b []byte
	var err error
	if b, err = json.Marshal(source); err != nil {
		return err
	}

	if err = json.Unmarshal(b, target); err != nil {
		return err
	}

	return nil
}
